#[macro_use]
extern crate log;

pub mod ext;
pub mod prelude;
pub mod router;

use std::convert::Infallible;
use std::{net::SocketAddr, sync::Arc};

use hyper::{
    service::{make_service_fn, service_fn},
    Body, Request as _Request, Response as _Response, Server,
};
use prelude::*;

type Request = _Request<Body>;
type Response = _Response<Body>;

pub use http::response::Builder;
pub use hyper::{Method, StatusCode};
use router::Router;

pub struct Engine {
    router: router::Router,
}

impl Engine {
    pub fn new(router: Router) -> Self {
        Self { router }
    }

    pub async fn run(self: Arc<Self>, addr: SocketAddr) -> Result {
        let make_svc = make_service_fn(move |_conn| {
            let engine = self.clone();
            async {
                Ok::<_, Infallible>(service_fn(move |req| {
                    let engine = engine.clone();
                    async move { engine.server_http(req).await }
                }))
            }
        });
        let server = Server::bind(&addr).serve(make_svc);
        server.await?;

        Ok(())
    }

    pub async fn server_http(&self, req: Request) -> Result<Response, Infallible> {
        Ok(self.router.handle(req))
    }
}
